#pragma once
#include "../CGIResource.h"

namespace Alice{
    class CGIVulkanDevice;
    struct CGIVulkanRHIExternalImageDeleteCallbackInfo;
    class CGIVulkanCommandListContext;
    extern VkFormat GVulkanSRGBFormat[EPixelFormat::PF_NUM];
    VkFormat UEToVkTextureFormat(EPixelFormat UEFormat, const bool bIsSRGB);
    VkImageAspectFlags GetAspectMaskFromUEFormat(EPixelFormat Format, bool bIncludeStencil, bool bIncludeDepth = true);
    VkImageViewType UETextureDimensionToVkImageViewType(ETextureDimension Dimension);
    
    class VulkanRenderTargetLayout
    {
    public:
        VkAttachmentReference ColorReferences[8];
        VkAttachmentReference DepthReference;

        // Depth goes in the "+1" slot, Depth resolve goes in the "+2 slot", and the Shading Rate texture goes in the "+3" slot.
        VkAttachmentDescription Desc[8 * 2 + 3];

        uint8 NumAttachmentDescriptions;
        uint8 NumColorAttachments;
        uint8 bHasDepthStencil;
        uint8 NumUsedClearValues;
        VulkanRenderTargetLayout(CGIVulkanDevice& InDevice, const CGIRenderPassInfo* RPInfo, VkImageLayout CurrentDepthLayout, VkImageLayout CurrentStencilLayout);
    };
    class CGIVulkanTexture : public CGITexture{
    public:
        VkImage mImage;
	    VkImageUsageFlags mImageUsageFlags;
        VkFormat mStorageFormat;  // Removes SRGB if requested, used to upload data
        VkFormat mViewFormat;  // Format for SRVs, render targets
        VkImageAspectFlags mFullAspectMask;
        VkImageAspectFlags mPartialAspectMask;
	    VkImageTiling mTiling;
	    VkImageLayout mDefaultLayout;
        CGIVulkanTexture();
        CGIVulkanTexture(CGIVulkanDevice& InDevice, const CGITextureCreateDesc& InCreateDesc, VkImage InImage, const CGIVulkanRHIExternalImageDeleteCallbackInfo& InExternalImageDeleteCallbackInfo);
        // Full includes Depth+Stencil
        inline VkImageAspectFlags GetFullAspectMask() const
        {
            return mFullAspectMask;
        }

        // Only Depth or Stencil
        inline VkImageAspectFlags GetPartialAspectMask() const
        {
            return mPartialAspectMask;
        }
        inline bool IsDepthOrStencilAspect() const
        {
            return (mFullAspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0;
        }
        inline bool SupportsSampling() const
        {
            return EnumHasAllFlags(GPixelFormats[(uint32)GetDesc().Format].Capabilities, EPixelFormatCapabilities::TextureSample) &&
                ((mImageUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) != 0);
        }
        inline VkImageViewType GetViewType() const
        {
            return UETextureDimensionToVkImageViewType(GetDesc().Dimension);
        }
        inline uint32 GetNumberOfArrayLevels() const
        {
            switch (GetViewType())
            {
            case VK_IMAGE_VIEW_TYPE_1D:
            case VK_IMAGE_VIEW_TYPE_2D:
            case VK_IMAGE_VIEW_TYPE_3D:
                return 1;
            case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
                return GetDesc().ArraySize;
            case VK_IMAGE_VIEW_TYPE_CUBE:
                return 6;
            case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
                return 6 * GetDesc().ArraySize;
            default:
                return 1;
            }
        }
        void SetInitialImageState(CGIVulkanCommandListContext& Context, VkImageLayout InitialLayout, bool bClear, const FClearValueBinding& ClearValueBinding, bool bIsTransientResource);
    };
    struct VulkanTextureView
    {
        VkImageView View   = VK_NULL_HANDLE;
        VkImage     Image  = VK_NULL_HANDLE;
        uint32      ViewId = 0;
    };
    class CGIVulkanView
    {
    public:
        CGIVulkanDevice& mDevice;
        VulkanTextureView mTextureView;
        CGIVulkanView(CGIVulkanDevice& InDevice, VkDescriptorType InDescriptorType);
        CGIVulkanView* InitAsTextureView(
          VkImage InImage
        , VkImageViewType ViewType
        , VkImageAspectFlags AspectFlags
        , EPixelFormat UEFormat
        , VkFormat Format
        , uint32 FirstMip
        , uint32 NumMips
        , uint32 ArraySliceIndex
        , uint32 NumArraySlices
        , bool bUseIdentitySwizzle = false
        , VkImageUsageFlags ImageUsageFlags = 0
        , VkSamplerYcbcrConversion SamplerYcbcrConversion = nullptr);
    };
}